package sound

import collection.mutable.{ArrayBuffer, ListBuffer}
import javax.sound.sampled.{AudioFormat, AudioSystem, SourceDataLine}
import java.io._
import audio.cords.{SimplestChart, Mike, Filter}
import org.jfree.ui.RefineryUtilities
import org.jfree.chart.{ChartFactory, JFreeChart}
import org.jfree.chart.renderer.xy.XYSplineRenderer
import java.awt.{Shape, Graphics2D}
import org.jfree.chart.entity.EntityCollection
import org.jfree.chart.plot.{CrosshairState, XYPlot, FastScatterPlot, PlotOrientation}
import java.awt.geom.Rectangle2D
import org.jfree.chart.axis.{ValueAxis, NumberAxis}
import org.jfree.data.xy.{XYDataset, XYSeries, XYSeriesCollection}
import audio.DFT

object LocalSimilar{
  def main(args:Array[String]){
    new LocalSimilar().shRecognize()
  }
}
class LocalSimilar{
  val rate = 11025

  def optFile(name:String, dirs:String*):File = {
    dirs.map( new File(_,name) ).find( _.exists ).get
  }

  def soundFileStreamOpen(fname:String) =
    new DataInputStream(new FileInputStream(optFile(fname,
      "/opt/project/simple-agent/sounds/", "c:/projects/scala-agent3/sounds")))

  def soundFileStream = soundFileStreamOpen("shshss.voice")
  def soundFileStream2 = soundFileStreamOpen("shshss2.voice")

  def shFilterKoefs = {
    val freqKoef = new Array[Double](65)
    for(i<-0 until freqKoef.size){
//      if(i<6 || i>15){
      if(i>=16 && i<=25){  // alternative shshsh audible interval
      //if(i>=26 && i<=35){ // cutting this from shshshsh makes it into soft sh'sh'sh'
        freqKoef(i)=1
      }
    }
    //for(i <- 6 to 15){ // shshsh audible
    //for(i <- 7 to 14){
    //for(i <- 8 to 13){
    //for(i <- 9 to 12){ // makes khkhkhkh sound from shshshsh
    //  freqKoef(i)=1
    //}
    freqKoef
  }

  def lowPass = {
    val freqKoef = new Array[Double](65)
    for(i<-0 until freqKoef.size){
      if(i>=2 && i<=9){
        freqKoef(i)=1
      }
    }
    filter(freqKoef) _
  }

  def filter(koefs: Array[Double])(sound: Array[Short]) = Filter.apply(sound, koefs, 41, 1)

  def filterX(n:Int, koefs: Array[Double])(sound: Array[Short]):Array[Short] = {
    if(n==0){
      sound
    }else{
      filterX(n-1,koefs)( filter(koefs)(sound) )
    }
  }

  def diod(sound: Array[Short]) = {
    val ret = new Array[Short](sound.size)
    for(i <- 0 until sound.size){
      //if(sound(i)>0){
        ret(i) = Math.abs(sound(i)) toShort
      //}
    }
    ret
  }

  def shFilter(sound : Array[Short]) = {
    Filter.apply(sound, shFilterKoefs, 41, 1)
  }

  class Recogn(tests:Seq[Array[Short]]){
    def check(snd:Array[Short]):Int={
      var counter=0;
      for(t<-tests){
        val c = 100*corr(t, snd)
        if(c>50){
          counter += 1
        }
      }
      counter
    }
  }

  def shRecognize() = {
    val len = 100
    val filtered = shFilter(soundFileData(soundFileStream))
    val tests = for(i<-28000.to(30000,50)) yield filtered.slice(i, i+len)
    //val test = new Recogn(filtered.slice(28000, 28000+len), filtered.slice(28200, 28200+len)) // shsh
    val test = new Recogn(tests)

    println("say shsh into microphone")
    var sampleRate: Int = 11025
    val mike = new Mike(sampleRate)
    val f = new Filter(mike, shFilterKoefs, 41, 1)

    val buf = new ArrayBuffer[Short]

    var i = 0
    var counter = 0
    while(true){
      buf += f.next()
      if(buf.size>=len){
        val alast = buf.slice(buf.size-len, buf.size).toArray
//        val c = 100*corr(test, alast)
//        if(c>30){
//          counter += 1
//        }
        counter += test.check(alast)
        i += 1
        if( i%1000==0 ){
          if( counter>580 ){
            println(i+ " "+counter+" ш")
          }
          counter = 0
        }
      }
    }

  }

  def fewFreqKoef = {
    val freqKoef = new Array[Double](65)
    for(i<-0 until freqKoef.size){
      if(i%15==2){
        freqKoef(i)=1
      }
    }
    freqKoef
  }

  def play(){
    val sound = soundFileData(soundFileStream)
    //val filtered = shFilter(sound)
    //val filtered = shFilter( filter(fewFreqKoef)(sound) )
    val filtered = filterX(2,fewFreqKoef)(sound)

    //val sound = soundFileStream2
    //val a = new Array[Byte](sound.available)
    //sound.readFully(a)
    val a = soundToBytes(filtered)

      var sampleRate: Int = 11025
      println("seconds: "+(a.size.toDouble/2/*bytes*//sampleRate))
      var line: SourceDataLine = AudioSystem.getSourceDataLine(new AudioFormat(sampleRate, 16, 1, true, true))
      line.open()
      line.start()
      line.write(a, 0, a.size)
  }

  def soundFileData(stream : DataInputStream) : Array[Short] = {
    val b = new ArrayBuffer[Short];
    val str = stream
    while(str.available>0){
      b += str.readShort
    }
    b.toArray
  }

  def soundToBytes(sound: Array[Short]) : Array[Byte] = {
    val b = new ByteArrayOutputStream
    val d = new DataOutputStream(b)
    sound.foreach(d.writeShort(_))
    b.toByteArray
  }

  def volume1(snd: Array[Short], from: Int, to: Int)={
    var i=from;
    var v=0;
    var sum=0
    while(i<to){
      var vi = snd(i)
      sum += (v-vi).abs
      v=vi
      i+=1
    }
    sum
  }

  def printVolumeStats(snd: Array[Short]){
    Iterator.range(0, snd.length-1000, 1000) foreach ((i:Int) => {println (i + "  "+ volume1(snd,i,i+1000))} )
  }

  def corr(a:Array[Short],b:Array[Short])={
    var suma,sumb,suma2,sumb2,sumab=0.0
    var i=0;
    val n = a.length
    while(i<n){
      val ai = a(i)
      val bi = b(i)
      suma += ai
      sumb += bi
      suma2 += ai*ai
      sumb2 += bi*bi
      sumab += ai*bi
      i+=1
    }

    (n*sumab - suma*sumb) / Math.sqrt(n*suma2 - suma*suma) / Math.sqrt(n*sumb2 - sumb*sumb)
  }

  def printCorr(){
    val len = 100
    //val all = soundFileData(soundFileStream2)
    val all = shFilter(soundFileData(soundFileStream2))

    val test = shFilter(soundFileData(soundFileStream)).slice(28000, 28000+len) // shsh
    //val test = all.slice(198000, 198000+len)
    //val test = all.slice(320000, 320000+len) // ssss
    //val test = soundFileData(soundFileStream).slice(320000, 320000+len) // ssss
    //val test = all.slice(44000, 44000+len) // noise

    println("printCorr()====")
    val sumGrp = new Array[Int](350)
    for( i <- 0 to 329000 ){
      //val beg = 28000+i
      //val beg = 125000+i
      val beg = 0+i
      val c = 100*corr(test, all.slice(beg, beg+len))
      if(c>30){
        sumGrp(  beg/1000 ) += 1
        //println(beg+" "+c )
      }
    }
    println("printCorr()====grp")
    for( i <- 0 until sumGrp.length ){
      //if( sumGrp(i)>0 ){
        val beg = i*1000
        println(beg+"   "+volume1(all,beg,beg+1000)+"  "+sumGrp(i))
      //}
    }
  }

  def printLocalCorr(){
    val all = soundFileData(soundFileStream)

    //val point = 320200
    val point = 28000
    for( i <- 2 to 1000 ){
      val before = all.slice(point-i, point)
      val after = all.slice(point, point+i)
      val c = 100*corr(before, after)
      if(c>20){
        printf("%d  %f  %n", i, c)
      }
    }

  }


}

